package org.codingq92.frame.springmvc.core;

import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.codingq92.frame.spring.ann.CusComponent;
import org.codingq92.frame.spring.config.BeanPostProcess;
import org.codingq92.frame.springmvc.ann.CusController;
import org.codingq92.frame.springmvc.ann.CusParam;
import org.codingq92.frame.springmvc.ann.CusRequestMapping;
import org.codingq92.frame.springmvc.bean.MyWebHandler;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;

@CusComponent
public class CusDispatcherServlet extends HttpServlet implements BeanPostProcess {

    private static final HashMap<String, MyWebHandler> handlerMap = new HashMap<>();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求实际的方法
        MyWebHandler webHandler = findHandler(req);
        if (null == webHandler) {
            resp.setContentType("text/html;charset=utf-8");
            resp.getWriter().write("<h1>404 Not Found!!!</h1>");
            return;
        }
        try {
            // 获取等待调用的方法
            Method method = webHandler.getMethod();
            // 获取所有的参数
            Parameter[] parameters = method.getParameters();
            Object[] args = new Object[parameters.length];
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[i];
                String name = parameter.getName();
                String val;
                CusParam annotation = parameter.getAnnotation(CusParam.class);
                if (null != annotation) {
                    val = req.getParameter(annotation.value());
                } else {
                    val = req.getParameter(name);
                }
                // 类型转换
                Class<?> type = parameter.getType();
                if (String.class.isAssignableFrom(type)) {
                    args[i] = val;
                } else if (Integer.class.isAssignableFrom(type) || int.class.isAssignableFrom(type)) {
                    args[i] = Integer.parseInt(val);
                } else {
                    args[i] = null;
                }
            }
            // 反射调用方法
            Object result = method.invoke(webHandler.getControllerBean(), args);
            switch (webHandler.getResultType()) {
                case MyWebHandler.JSON -> {
                    resp.setContentType("application/json;charset=utf-8");
                    resp.getWriter().write(JSON.toJSONString(result));
                }
                case MyWebHandler.HTML -> {
                    resp.setContentType("text/html;charset=utf-8");
                    resp.getWriter().write(result.toString());
                }
                case MyWebHandler.VIEW -> {

                }
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private MyWebHandler findHandler(HttpServletRequest req) {
        String requestURI = req.getRequestURI();
        return handlerMap.get(requestURI);
    }

    /**
     * 在Bean初始化完成后进行后处理，用于扫描带有CusController注解的类，
     * 并解析类和方法上的CusRequestMapping注解，构建请求URL与处理器的映射关系
     *
     * @param bean     Spring容器中的Bean实例
     * @param beanName Bean的名称
     * @return 处理后的Bean实例
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        boolean present = bean.getClass().isAnnotationPresent(CusController.class);
        if (present) {
            // 获取类级别的请求映射路径
            String controllerUrl = "";
            CusRequestMapping annotation = bean.getClass().getAnnotation(CusRequestMapping.class);
            if (null != annotation && null != annotation.value()) {
                controllerUrl = annotation.value();
            }
            // 遍历所有方法，构建完整的请求映射关系
            for (java.lang.reflect.Method method : bean.getClass().getMethods()) {
                CusRequestMapping methodAnnotation = method.getAnnotation(CusRequestMapping.class);
                if (null != methodAnnotation && null != methodAnnotation.value()) {
                    String methodUrl = methodAnnotation.value();
                    String reqUrl = controllerUrl + methodUrl;
                    MyWebHandler handler = handlerMap.put(reqUrl, new MyWebHandler(bean, method));
                    if (null != handler) {
                        throw new RuntimeException("url: " + reqUrl + "重复.");
                    }
                }
            }
        }
        return bean;
    }

}
